﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using E4D.AppFabric.Entities;
using Microsoft.ApplicationServer.Caching.AdminApi;
using E4D.AppFabric.Entities.Cache_Host;

namespace MDCAdminTool
{
    public enum Eviction
    {
        None,
        LRU
    }

    public class MdcCache : PowerShellBase<CacheHost, CacheRegion>
    {
        #region Fields
        private bool _IsHighAvailability;
        private Eviction _Eviction;
        private long _TTL;
        private bool _Expirable;
        private bool _NotificationsEnabled;
        private NamedCacheStats _NamedCacheStats;
        private string _CacheType;
        private Collection<CacheRegion> _CacheRegions;
        #endregion

        #region Properties
        public string CacheType
        {
            get { return _CacheType; }
            set { _CacheType = value; OnPropertyChanged("CacheType"); }
        }
        public bool IsHighAvailability
        {
            get { return _IsHighAvailability; }
            set { _IsHighAvailability = value; OnPropertyChanged("IsHighAvailability"); }
        }
        public Eviction Eviction
        {
            get { return _Eviction; }
            set { _Eviction = value; OnPropertyChanged("Eviction"); }
        }
        public long TTL
        {
            get { return _TTL; }
            set { _TTL = value; OnPropertyChanged("TTL"); }
        }
        public bool IsExpirable
        {
            get { return _Expirable; }
            set { _Expirable = value; OnPropertyChanged("Expirable"); }
        }
        public Dictionary<string, string[]> HostRegionMap { set; get; }
        public NamedCacheStats NamedCacheStats
        {
            get { return _NamedCacheStats; }
            set { _NamedCacheStats = value; OnPropertyChanged("NamedCacheStats"); }
        }
        public bool NotificationsEnabled
        {
            get { return _NotificationsEnabled; }
            set { _NotificationsEnabled = value; OnPropertyChanged("NotificationsEnabled"); }
        }
        public Collection<CacheRegion> CacheRegions
        {
            get { return _CacheRegions; }
            set { _CacheRegions = value; OnPropertyChanged("CacheRegions"); }
        }

        #endregion

        #region Constructors
        public MdcCache(string name)
        {
            Type = MDCAdminTool.CacheType.CacheName;
            Name = name;
        }

        public MdcCache(CacheHost host, string name)
            : this(name)
        {

            //IsHighAvailability  = false;
            //Eviction            = Eviction.LRU;
            //TTL                 = 10;
            //NotExpirable        = true;
            Parent = host;
            CacheRegions = new Collection<CacheRegion>();
            Params = new Dictionary<string, object>
                        {
                            {"CacheName"  , Name}
                        };

            Output = host.Output;

            LoadConfig();
            LoadRegions();

        }
        public MdcCache(CacheHost host, CacheInfo cacheInfo)
            : this(host, cacheInfo.CacheName)
        {

        }
        public MdcCache(CacheHost host, string name, bool notificationsEnabled, bool isHighAvailability, Eviction eviction, int Ttl, bool isExpirable)
            : this(host, name)
        {
            IsHighAvailability = isHighAvailability;
            Eviction = eviction;
            TTL = Ttl;
            IsExpirable = !isExpirable;
            NotificationsEnabled = notificationsEnabled;
        }
        #endregion

        #region PowerShell Commands

        /// <summary>
        /// Returns a list of all regions in the cache cluster or only those in a named cache.
        /// </summary>
        /// <returns>Returns a list of all regions in the cache cluster or only those in a named cache.</returns>
        public void LoadRegions()
        {
            var r = Invoke("Get-CacheRegion", Params);
            if (r == null || r.Count == 0)
            {
                CacheRegions = null;
                return;
            }
            var result = GetRegionResult(r);
            CacheRegions = result;
        }

        private Collection<CacheRegion> GetRegionResult(IEnumerable<PSObject> r)
        {
            var result = new Collection<CacheRegion>();

            foreach (var region in r)
            {
                var regionName = (string)region.Properties["RegionName"].Value;
                
                if (!regionName.StartsWith("Default_Region_"))
                {
                    result.Add(new CacheRegion
                                   (
                                   regionName,
                                   (string)region.Properties["Role"].Value,
                                   (int)region.Properties["PortNo"].Value,
                                   this
                                   ));
                }
            }
            return result;
        }

        /// <summary>
        /// Add Region to cache name.
        /// </summary>
        /// <param name="region">Region Name</param>
        /// <param name="evictionOn">Eviction On</param>
        public void AddRegion(string region, bool evictionOn)
        {
            try
            {
                var client = CacheClientFactory.GetCache(this);

                if (client != null)
                {
                    Log(new PowerShellCommand { CommandName = string.Format(@"DataCache.CreateRegion( {0} )", region) });
                    client.CreateRegion(region);
                }
            }
            catch (Exception ex)
            {
                Log(new PowerShellCommand { CommandName = ex.Message });
            }
            LoadRegions();
        }

        /// <summary>
        /// Load statistics of a named cache
        /// </summary>
        public override CacheStats LoadStatistics()
        {
            var r = Invoke("Get-CacheStatistics", Params);
            Collection<NamedCacheStats> result = r.BuildNamedCacheStats();

            if (result.Count > 0)
                NamedCacheStats = result[0];
            return NamedCacheStats;
        }

        /// <summary>
        /// Returns the configuration details for the named cache
        /// </summary>
        /// <returns>Returns the configuration details for the named cache</returns>
        public override void LoadConfig()
        {
            try
            {
                var r = Invoke("Get-CacheConfig", Params);
                if (r != null && r.Count > 0)
                {
                    var result = r[0];
                    if (result != null)
                    {
                        Name = Convert.ToString(result.Properties["CacheName"].Value);
                        Eviction = (Eviction)Enum.Parse(typeof(Eviction), result.Properties["EvictionType"].Value.ToString());
                        IsExpirable = Convert.ToBoolean(result.Properties["IsExpirable"].Value);
                        NotificationsEnabled = Convert.ToBoolean(result.Properties["NotificationsEnabled"].Value);
                        TTL = Convert.ToInt64(result.Properties["TimeToLive"].Value);
                        IsHighAvailability = Convert.ToBoolean(result.Properties["Secondaries"].Value);
                        CacheType = Convert.ToString(result.Properties["CacheType"].Value);
                    }
                }
            }
            catch (Exception ex)
            {
                AddResultToLog(ex.Message);
            }
        }

        /// <summary>
        /// Updates the configuration settings of the named cache
        /// </summary>
        public override void SaveConfig()
        {
            var p = new Dictionary<string, object>
                        {
                            {"CacheName"    , Name},
                            {"Secondaries"  , IsHighAvailability ? 1 : 0 },
                            {"TimeToLive"   , TTL},
                            {"NotificationsEnabled"  , NotificationsEnabled},
                            {"Eviction"     , Eviction},
                            {"Expirable"    , IsExpirable}
                        };

            var r = Invoke("Set-CacheConfig", p);
        }

        public override void Add(CacheEntityBase item)
        {
            if (item is CacheRegion) Add(item as CacheRegion);
        }
        public override void Add(CacheRegion region)
        {
            AddRegion(region.Name, region.EvictionOn);
        }
        public override void Remove(CacheRegion region)
        {
            Remove(region as CacheEntityBase);
        }
        public override void Remove(CacheEntityBase item)
        {
            try
            {
                Log("DataCliet.RemoveRegion(...)");
                var dc = CacheClientFactory.GetCache(this);
                if (dc == null) return;

                dc.RemoveRegion(item.Name);
            }
            catch (Exception ex)
            {
                Log(new PowerShellCommand { CommandName = ex.Message });
            }
            LoadRegions();
        }
        #endregion

        #region Not Implemented
        public override void Start()
        {
            throw new NotImplementedException();
        }
        public override void Stop()
        {
            throw new NotImplementedException();
        }
        public override void LoadChildren()
        {
            throw new NotImplementedException();
        }
        #endregion




    }
}
